#include "client.h"
int main() {
	char cmd[128];
	int length;
	char ipstr[15];

	do {
		printf("Enter server ip(default localhost):");
		gets(ipstr);
		if (strlen(ipstr) == 0) {
			strcpy(ipstr, LOCALHOST);
		}
		printf("connect to ip: ");
		puts(ipstr);
	} while (-1 == connect_cmd_channel(ipstr));
	while (1) {
		printf("ftpClient>");
		gets(cmd);
		//	trim_left(cmd); //去掉左边的空格
		length = strlen(cmd);
		if (0 == strcmp(cmd, BYE)) {
			if (write(cfp_cmd, cmd, strlen(cmd)) == -1) {
				printf("Can't disconnect with server!\n");
				return -1;
			}
			if (-1 != cfp_data) //cfp_data不为-1，则表示建立了data通道
				close(cfp_data);
			close(cfp_cmd);
			flag_prt = FLAG_PRT_NOTCONNECTED;
			printf("close your connect with server!\nBYE BYE !\n");
			break;

		} else if (0 == strcmp(cmd, DIR)) {
			if (check_prt() == FLAG_PRT_CONNECTED) { //connected already
				send_dir();
			}
		} else if (length > 3) {
			char head[5];
			strncpy(head, cmd, 4);
			head[4] = '\0';
			if (strcmp(head, PRT) == 0) {
				send_prt(cmd);
			} else if (strcmp(head, GET) == 0) {
				send_get_file(cmd);
			} else {
				show_invailed();
			}
		} else {
			show_invailed();
		}
	}

	return 0;
}

int send_prt(char* cmd) {
#ifdef TEST
	printf("before send prt");
#endif	
	int portnum = atoi(cmd + 4);
	if (portnum < 1024 || portnum > 65535 || portnum == PORTNUM_CMD) {
		printf("port number must be between 1024 to 65535 and cannot %d.\n",
		PORTNUM_CMD);
		return;
	}
	int sfp_data = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == sfp_data) {
		printf("create data channel fail!try again!\n");
		return -1;
	}
	struct sockaddr_in s_add_data, c_add_data;
	bzero(&s_add_data, sizeof(struct sockaddr_in));
	s_add_data.sin_family = AF_INET;
	s_add_data.sin_addr.s_addr = htonl(INADDR_ANY);
	s_add_data.sin_port = htons(portnum);
	if (-1
			== bind(sfp_data, (struct sockaddr *) (&s_add_data),
					sizeof(struct sockaddr))) {
		printf("bind data fail!\n");
		return -1;
	}
	if (-1 == listen(sfp_data, 5)) {
		printf("listen data channel fail!\n");
		return -1;
	}
	if (send_cmd(cmd) == FLAG_SERVER_OK) {
		cfp_data = accept(sfp_data, (struct sockaddr *) (&c_add_data),
				&sin_size); //与客户端数据通道连接
		if (-1 == cfp_data) {
			perror("accept data channel fail!");
			return -1;
		}
		printf("build data channel success!\n");
		flag_prt = FLAG_PRT_CONNECTED;
		printf("Send 'DIR' command now...\n");
		send_dir();
	}
}

void send_get_file(char* cmd) {
#ifdef TEST
	printf("before send get file: %s\n", cmd);
#endif
	if (send_cmd(cmd) == FLAG_SERVER_OK) {
		char sizestr[16];
		char temp[1];
		int i;
		for (i = 0; i < 16; i++) {
			if (-1 == read(cfp_data, temp, 1)) {
				printf("accept file size error ! plese try again!\n");
				return;
			} else {
				if (temp[0] == ' ') {
					sizestr[i] = '\0';
					break;
				} else
					sizestr[i] = temp[0];
			}
		}
		long size = atoi(sizestr);
#ifdef TEST
		printf("size:%s\n",sizestr);
#endif
		char file[size];
		if (-1 == recv(cfp_data, file, size, MSG_WAITALL)) {
			printf("accept file stream error\n");
			return;
		}
		char* filename = cmd + 4;
		int fp = open(filename, O_WRONLY | O_TRUNC | O_CREAT);
#ifdef TEST
		int j;
		for(j=0;j<size;j++) {
			printf("%u ",file[j]);
		}
		printf("\nfile:%s\n",file);
#endif
		if (-1 == write(fp, file, size)) {
			printf("write local file error !\n");
			return;
		} else {
			chmod(filename,
					S_IWUSR | S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH | S_IRUSR); //设为可读可写
			printf("write file successfully !\n");
			return;
		}

	} else {
		printf("no this file!\n");
		return;
	}
}
int check_prt() {
	if (FLAG_PRT_CONNECTED == flag_prt)
		return FLAG_PRT_CONNECTED;
	else {
		printf(
				"The command will be not responsed until built data channel,please 'PRT port'first !\n");
		return FLAG_PRT_NOTCONNECTED;
	}
}
void send_dir() {
	char buf[128];
	int length;
	if (send_cmd(DIR) == FLAG_SERVER_OK) {
		char sizestr[16];
		char temp[1];
		int i;
		for (i = 0; i < 16; i++) {
			if (-1 == read(cfp_data, temp, 1)) {
				printf("get director information error! plese try again!\n");
				return;
			} else {
				if (temp[0] == ' ') {
					sizestr[i] = '\0';
					break;
				} else
					sizestr[i] = temp[0];
			}
		}
		long size = atoi(sizestr);
		char dirstr[size];
		if (-1 == read(cfp_data, dirstr, size)) {
			printf("accept director information error\n");
			return;
		}
		fwrite(dirstr, sizeof(char), size, stdout);
		//dirstr[size]='\0';
		//printf("%s",dirstr);
	} else {
		printf("Server return error!\n");
	}
}
int connect_cmd_channel(char* serverip) {
	int recbytes;
	int sin_size;
	char buffer[1024] = { 0 };
	struct sockaddr_in s_add_cmd, c_add_cmd;

//	printf("Hello,welcome to client !\r\n");

	cfp_cmd = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == cfp_cmd) {
		printf("socket fail ! try again \n");
		return -1;
	}
#ifdef TEST
	printf("socket ok !\n");
#endif
	memset(&s_add_cmd, 0, sizeof(struct sockaddr_in));
	s_add_cmd.sin_family = AF_INET;
	s_add_cmd.sin_addr.s_addr = inet_addr(serverip);
	s_add_cmd.sin_port = htons(PORTNUM_CMD);
	if ((-1
			== connect(cfp_cmd, (struct sockaddr *) (&s_add_cmd),
					sizeof(struct sockaddr)))) {
		printf("connect fail! try again\n");
		return -1;
	}
	printf(
			"connect command channel with server success!\nPlease 'PRT port_num' to build data channel now\n");
	return 0;
}

int send_cmd(char* cmd) {
	if (write(cfp_cmd, cmd, strlen(cmd)) == -1)
		return FLAG_CLIENT_COMMIT_FAIL;
	char ack[3] ;
	int ack_flag = recv(cfp_cmd, ack, 2, MSG_WAITALL);
	ack[2] = '\0';
#ifdef TEST
	printf("length : %d\n", ack_flag);
	printf("%s\n", ack);
#endif
	if (2 == ack_flag) {
		if (strcmp(ack, "OK") == 0)
			return FLAG_SERVER_OK;
		if (strcmp(ack, "ER") == 0)
			return FLAG_SERVER_ER;
	}
	return FLAG_SERVER_NOACK;
}

void trim_left(char* str) {
	int length = strlen(str);
	int i;
	for (i = 0; i < length; i++) {
		if ((*str) == ' ')
			++str;
		else
			break;
	}
}

void show_invailed() {
	printf("invail command ,only support 'GET','BYE','DIR','PRT' \n");
}
